package mqttsender

import (
	"context"
	"energy-amiot-platform/core"
	"energy-amiot-platform/model/dbspo"
	"energy-amiot-platform/model/redispo"
	"energy-amiot-platform/model/request"
	"energy-amiot-platform/model/response"
	"energy-amiot-platform/repository"
	"energy-amiot-platform/utils"
	"energy-amiot-platform/utils/hash"
	"energy-amiot-platform/utils/respout"
	"errors"
	"fmt"
	"log/slog"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"golang.org/x/exp/rand"
	"gorm.io/gorm"
)

var (
	salt       = "hkfg+"
	moduleCode = 4
)

// 创建mqtt推送帐户
// 只能创建一次
// 平台管理功能（必须进入管理平台页面）
// @Tags 推送管理
// @Summary 启用推送
// @Description 启用推送
// @Accept  json
// @Product json
// @Param   input body   request.MqttSenderCreateReq{}  true		"入参"
// @Success 200 {object} response.Response{result=response.MqttSenderAddResult} "Ok"
// @Router /mqtt/sender [post]
func create(ctx *gin.Context) {
	var handleCode = 1
	var req request.MqttSenderCreateReq
	err := ctx.ShouldBindJSON(&req)
	if err != nil {
		respout.SendError(ctx, core.APP.Code, moduleCode, handleCode, 0, respout.StrErrParse, err, nil)
		return
	}

	core.DATABASE.Cur().Transaction(func(tx *gorm.DB) error {
		tx1, sender := repository.MQTTSENDER.FindByProductId(tx, req.ProductId)
		if tx1.Error != nil {
			if tx1.Error != gorm.ErrRecordNotFound {
				respout.SendError(ctx, core.APP.Code, moduleCode, handleCode, 1, respout.StrFail, tx1.Error, nil)
				return tx1.Error
			}
		}

		if sender.ProductId != 0 {
			err2 := errors.New("重复创建")
			respout.SendError(ctx, core.APP.Code, moduleCode, handleCode, 2, respout.StrFail, err2, nil)
			return err2
		}

		r := rand.New(rand.NewSource(uint64(time.Now().UnixNano())))
		c := r.Int()%5 + 1
		key, _ := utils.RandStringBytesCrypto(8 + c)
		secret, _ := utils.RandStringBytesCrypto(8 + c)
		shapwd := hash.Shapwd(secret, salt)

		slog.Info(fmt.Sprintf("key:%s;secret:%s;shapwd:%s", key, secret, shapwd))
		user := redispo.AuthUser{
			Salt:         salt,
			PasswordHash: shapwd,
			Super:        false,
			Use:          "pusher",
		}
		u := uuid.New()
		replace := strings.Replace(u.String(), "-", "", -1)
		device := redispo.Device{
			DeviceID:  replace,
			ProductID: req.ProductId,
		}
		topic1 := fmt.Sprintf(core.TopicPatternDeviceSetPropertyPost, req.ProductId)
		//topic2 := fmt.Sprintf(core.TopicPatternDeviceSetPropertySet, req.ProductId)
		topic3 := fmt.Sprintf(core.TopicPatternDeviceSetEventReg, req.ProductId)
		topic4 := fmt.Sprintf(core.TopicPatternDeviceSetEventAct, req.ProductId)
		topic5 := fmt.Sprintf(core.TopicPatternDeviceSetEventDel, req.ProductId)
		topic6 := fmt.Sprintf(core.TopicPatternDeviceSetEventOn, req.ProductId)
		topic7 := fmt.Sprintf(core.TopicPatternDeviceSetEventOff, req.ProductId)

		sender.ProductId = req.ProductId
		sender.MqttUserName = key
		sender.MqttUserPassword = secret
		sender.MqttUserEnable = true

		tx1 = tx.Create(&sender)
		if tx1.Error != nil {
			respout.SendError(ctx, core.APP.Code, moduleCode, handleCode, 3, respout.StrFail, tx.Error, nil)
			return tx1.Error
		}

		pipeline := core.REDIS.Client.Pipeline()
		background := context.Background()
		pipeline.HMSet(background, "mqtt_user:"+key, user)
		pipeline.HMSet(background, "mqtt_device:"+key, device)
		pipeline.HSet(background, "mqtt_acl:"+key, topic1, "subscribe")
		//pipeline.HSet(background, "mqtt_acl:"+key, topic2, "publish")
		pipeline.HSet(background, "mqtt_acl:"+key, topic3, "subscribe")
		pipeline.HSet(background, "mqtt_acl:"+key, topic4, "subscribe")
		pipeline.HSet(background, "mqtt_acl:"+key, topic5, "subscribe")
		pipeline.HSet(background, "mqtt_acl:"+key, topic6, "subscribe")
		pipeline.HSet(background, "mqtt_acl:"+key, topic7, "subscribe")

		_, err = pipeline.Exec(background)
		if err != nil {
			respout.SendError(ctx, core.APP.Code, moduleCode, handleCode, 4, respout.StrFail, err, nil)
			return err
		}

		var result response.MqttSenderAddResult
		result.AppId = key
		result.AppSecret = secret
		respout.Ok(ctx, result)

		return nil
	})
}

// 显示当前产品的mqtt推送密码
// mqtt推送帐户只有第一次建立才能获取用户和密码，再次获取需要用户手动操作
// 平台管理功能（必须进入管理平台页面）
// @Tags 推送管理
// @Summary 显示推送密钥
// @Description 显示推送密钥
// @Product json
// @Param   productId query   string  true		"产品标识"
// @Success 200 {object} response.Response{result=string} "Ok"
// @Router /mqtt/sender/show [post]
func showSecret(ctx *gin.Context) {
	var handleCode = 2
	productId, err := strconv.ParseUint(ctx.Query("productId"), 10, 64)
	if err != nil {
		respout.SendError(ctx, core.APP.Code, moduleCode, handleCode, 0, respout.StrErrParse, err, nil)
		return
	}

	db := core.DATABASE.Cur()
	var secret string
	err = db.Raw("select mqtt_user_password from ht_mqtt_sender where product_id=?", productId).Scan(&secret).Error
	if err != nil {
		respout.SendError(ctx, core.APP.Code, moduleCode, handleCode, 1, respout.StrFail, err, nil)
		return
	}
	if secret == "" {
		respout.SendError(ctx, core.APP.Code, moduleCode, handleCode, 2, respout.StrFail, errors.New("用户不存在"), nil)
		return
	}

	respout.Ok(ctx, secret)
}

// 重置当前产品的mqtt推送密码
// mqtt推送帐户只有第一次建立才能获取用户和密码，再次获取需要用户手动操作
// 平台管理功能（必须进入管理平台页面）
// @Tags 推送管理
// @Summary 改变推送密钥
// @Description 改变推送密钥
// @Product json
// @Param   productId query   string  true		"产品标识"
// @Success 200 {object} response.Response{result=string} "Ok"
// @Router /mqtt/sender/change [post]
func changeSecret(ctx *gin.Context) {
	var handleCode = 3
	var req request.MqttSenderAppSecretShowReq
	err := ctx.ShouldBindJSON(&req)
	if err != nil {
		respout.SendError(ctx, core.APP.Code, moduleCode, handleCode, 0, respout.StrErrParse, err, nil)
		return
	}

	var sender dbspo.MqttSender
	background := context.Background()
	core.DATABASE.Cur().Transaction(func(tx *gorm.DB) error {
		tx1 := tx.First(&sender, "product_id=?", req.ProductId)
		switch {
		case tx1.Error == gorm.ErrRecordNotFound:
			err2 := errors.New("帐户不存在，请先开启")
			respout.SendError(ctx, core.APP.Code, moduleCode, handleCode, 1, respout.StrFail, err2, nil)
			return err2
		case tx.Error != nil:
			respout.SendError(ctx, core.APP.Code, moduleCode, handleCode, 2, respout.StrFail, tx.Error, nil)
			return tx1.Error
		}

		r := rand.New(rand.NewSource(uint64(time.Now().UnixNano())))
		c := r.Int()%5 + 1
		secret, _ := utils.RandStringBytesCrypto(8 + c)
		shapwd := hash.Shapwd(secret, salt)
		sender.MqttUserPassword = secret
		tx1 = tx.Save(&sender)
		if tx.Error != nil {
			respout.SendError(ctx, core.APP.Code, moduleCode, handleCode, 3, respout.StrFail, tx.Error, nil)
			return tx1.Error
		}

		pipeline := core.REDIS.Client.Pipeline()
		key := "mqtt_user:" + sender.MqttUserName
		pipeline.HSet(background, key, "password_hash", shapwd).Err()
		_, err = pipeline.Exec(background)
		if err != nil {
			respout.SendError(ctx, core.APP.Code, moduleCode, handleCode, 4, respout.StrFail, tx.Error, nil)
			return err
		}

		respout.Ok(ctx, secret)
		return nil
	})
}
